package com.david.auth.jwt;

import cn.hutool.core.util.RandomUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.apache.commons.lang3.StringUtils;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

public class JwtToken {
    /**
     * token秘钥，请勿泄露，请勿随便修改 backups:1QaE4RgY@#%
     */
    private static final String SECRET = "1QaE4RgY@#%";
    /**
     * token 过期时间: 10天
     */
    public static final int calendarField = Calendar.SECOND;
    private static final int calendarInterval = 30;

    /**
     * JWT生成Token.<br/>
     * JWT构成: header, payload, signature
     *
     * @param uid              登录成功后用户唯一标志uid, 参数uid不可传空
     * @param aud              接收jwt方
     * @param iss              jwt发行方
     * @param sub              subject（登录帐号）
     * @param expired_interval 过期时间间隔
     * @param private_key      签名私密
     */
    public static String createToken(String uid, String aud, String iss, String sub, int expired_interval, Map<String, String> claimMap, String private_key) throws Exception {
        if (StringUtils.isBlank(uid) || StringUtils.isBlank(aud)) {
            throw new Exception("登录用户唯一标识和接收方不能为空");
        }
        // expire time
        Calendar expTime = Calendar.getInstance();
        expTime.add(calendarField, expired_interval);

        // header Map
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");    //HS256
        map.put("typ", "JWT");

        // build token
        JWTCreator.Builder bulid = JWT.create().withHeader(map) // header
                .withClaim(JwtPayloadConstants.PRIVATE_UID, uid) // payload
                .withIssuer(iss)        //iss
                .withSubject(sub)
                .withAudience(aud)      // aud
                .withIssuedAt(Calendar.getInstance().getTime()) // sign time
                .withExpiresAt(expTime.getTime()) // expire time
                .withClaim("rnd", RandomUtil.randomInt(10,100)); //生成随机数，防止同用户的token相同

        //设置额外claim
        if (claimMap != null && claimMap.size() > 0) {
            for (String s : claimMap.keySet()) {
                bulid.withClaim(s, claimMap.get(s));
            }
        }

        // signature
        String token = bulid.sign(Algorithm.HMAC256(private_key));

        return token;
    }

    public static String createToken(Map<String, String> claimMap, String private_key){
        // header Map
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");    //HS256
        map.put("typ", "JWT");

        // build token
        JWTCreator.Builder bulid = JWT.create().withHeader(map);

        if (claimMap != null && claimMap.size() > 0) {   //设置额外claim
            for (String s : claimMap.keySet()) {
                bulid.withClaim(s, claimMap.get(s));
            }
        }

        String token = bulid.sign(Algorithm.HMAC256(private_key)); // signature
        return token;
    }



    /**
     * 拆解JWT
     *
     * @param token
     * @return
     */
    public static DecodedJWT decode(String token) {
        return JWT.decode(token);
    }

    /**
     * 校验token
     *
     * @param jwt
     * @param private_key
     * @throws JWTVerificationException
     */
    public static void verifyToken(DecodedJWT jwt, String private_key) throws JWTVerificationException {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(private_key))
                .withSubject(jwt.getSubject())
                .build();
        verifier.verify(jwt.getToken());
    }

    /**
     * 解密Token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static Map<String, Claim> verifyToken(String token) throws JWTVerificationException {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        DecodedJWT jwt = verifier.verify(token);
        return jwt.getClaims();
    }

    /**
     * 解密Token
     *
     * @param token
     * @param private_key 签名私密
     * @return
     * @throws Exception
     */
    public static Map<String, Claim> verifyToken(String token, String private_key) throws JWTVerificationException {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(private_key)).build();
        DecodedJWT jwt = verifier.verify(token);
        return jwt.getClaims();
    }


}
